class Density {
  int DIM;
  int * L;                               
  int * dens;
  int  * origin;
  int size;
  bool check_point(int * pos);
  int list_site(int * pos);
 public:
  Density(int d,int * L,int * orig);
  ~Density();
  void print_data();
  void increase(int * pos);
  void decrease(int *pos);
  void print();
  void print(ofstream);
  int get(int * pos);
  void set(int * pos,int value);
  void insert_walk(Walk);
  void remove_walk(Walk);
};

Density::Density(int d, int * l, int * orig) {
  int i,j,k;
  DIM=d;
  origin= new int[DIM];
  L= new int[DIM];
  size=1;
  for (i=0;i<DIM;i++) {
    L[i]=l[i];
    origin[i]=orig[i];
    size=size*L[i];
  }
  dens = new int[size];
  for (i=0;i<size;i++) {
    dens[i]=0;
  }
}
  
Density::~Density() {
  delete [] dens;
  delete [] L;
  delete [] origin;
}

void Density::print_data() {
  int i;
  cout << "matrix dimensions: ";
  for (i=0;i<DIM;i++) {
    cout << L[i] << "\t";
  }
  cout << "\npoint of origin: ";
  for (i=0;i<DIM;i++) {
    cout << origin[i] << "\t";
  }
  cout << "\n";
}
  
bool Density::check_point(int * pos) {
  int i;
  for (i=0;i<DIM;i++) {
    if ((pos[i]+origin[i]>L[i]-1) || (pos[i]+origin[i]<0)) return 0;
  }
  return 1;
}

int Density::list_site(int * pos) {
  int i,j,m,p;
  m=0;
  for (i=0;i<DIM;i++) {
    p=1;
    for (j=i+1;j<DIM;j++) {
      p=p*L[j];
    }
    m=m+(pos[i]+origin[i])*p;
  }
  return m;
}


void Density::increase(int * pos) {
  if (check_point(pos)) {
    int m=list_site(pos);
    dens[m]++;
    }
  //else cout << "point out of bouds\n";
}

void Density::decrease(int * pos) {
  if (check_point(pos)) {
    int m=list_site(pos);
    dens[m]--;
    }
  else cout << "point out of bouds\n";
}

void Density::print() {
  int i;
  for (i=0;i<size;i++) {
    cout << dens[i] << " ";
  }
}

void Density::print(ofstream out_file) {
  int i;
  for (i=0;i<size;i++) {
    out_file << dens[i] << " ";
  }
}

int Density::get(int * pos) {
  int m = list_site(pos);
  return dens[m];
}

void Density::set(int * pos,int value) {
  int m=list_site(pos);
  dens[m]=value;
}
			 
void Density::insert_walk(Walk walk1) {
  int i;
  int * pos;
  pos = new int[DIM];
  for (i=0;i<walk1.get_length()+1;i++) {
    walk1.get_pos(i,pos);
    increase(pos);
  }
  delete [] pos;
}

void Density::remove_walk(Walk walk1) {
  int i;
  int * pos;
  pos = new int[DIM];
  for (i=0;i<walk1.get_length()+1;i++) {
    walk1.get_pos(i,pos);
    decrease(pos);
  }
  delete [] pos;
}
